package com.esfak47.mediafetcher.app.config;

import com.esfak47.common.extension.ExtensionLoader;
import com.esfak47.common.job.Job;
import com.esfak47.common.job.JobManager;
import com.esfak47.mediafetcher.app.Application;
import com.esfak47.mediafetcher.app.extension.SpringExtensionFactory;
import com.esfak47.mediafetcher.app.service.MockupApi;
import com.esfak47.mediafetcher.app.service.impl.DefaultJobManagerImpl;
import com.esfak47.mediafetcher.core.service.CrawlerService;
import com.esfak47.mediafetcher.core.service.JobBuilder;
import com.esfak47.mediafetcher.core.service.MediaProvider;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import retrofit2.Retrofit;
import retrofit2.adapter.java8.Java8CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

/**
 * @author tony
 */
@Configuration
public class BeanConfig implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringExtensionFactory.addApplicationContext(applicationContext);
    }

    @ConditionalOnMissingBean(MockupApi.class)
    @Bean(value = "mockupApi")
    public MockupApi getMockupApi() {
        Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://easy-mock.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(Java8CallAdapterFactory.create())
            .build();
        return retrofit.create(MockupApi.class);
    }

    @Bean(value = "crawlerService")
    public CrawlerService crawlerService() {
        ExtensionLoader<CrawlerService> extensionLoader =
            ExtensionLoader.getExtensionLoader(CrawlerService.class, Application.pluginClassLoader);
        return extensionLoader.getAdaptiveExtension();
    }

    @Bean("ioExecutor")
    public Executor getIOExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setThreadNamePrefix("io");
        threadPoolTaskExecutor.setCorePoolSize(10);
        threadPoolTaskExecutor.setQueueCapacity(1024);
        threadPoolTaskExecutor.setKeepAliveSeconds(5000);
        threadPoolTaskExecutor.setMaxPoolSize(20);
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;

    }

    @Bean("jobExecutor")
    public Executor getJobExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setThreadNamePrefix("job");
        threadPoolTaskExecutor.setCorePoolSize(10);
        threadPoolTaskExecutor.setQueueCapacity(1024);
        threadPoolTaskExecutor.setKeepAliveSeconds(5000);
        threadPoolTaskExecutor.setMaxPoolSize(20);
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;

    }

    @Bean("jobContainer")
    public Map<String, Job> jobContainer() {
        return new ConcurrentHashMap<>();
    }

    @Bean("futureMap")
    public Map<String, CompletableFuture> futureMap() {
        return new ConcurrentHashMap<>();
    }

    @Bean("jobManager")
    public JobManager jobManager() {
        ExtensionLoader<JobManager> extensionLoader =
            ExtensionLoader.getExtensionLoader(JobManager.class, Application.pluginClassLoader);
        extensionLoader.addExtension("default", DefaultJobManagerImpl.class);
        return extensionLoader.getExtension("default");
    }

    @Bean("jobBuilder")
    public JobBuilder jobBuilder() {
        ExtensionLoader<JobBuilder> jobBuilderExtensionLoader =
            ExtensionLoader.getExtensionLoader(JobBuilder.class);
        return jobBuilderExtensionLoader.getAdaptiveExtension();
    }

    @Bean("mediaProvider")
    public MediaProvider mediaProvider() {
        ExtensionLoader<MediaProvider> extensionLoader =
            ExtensionLoader.getExtensionLoader(MediaProvider.class, Application.pluginClassLoader);
        return extensionLoader.getAdaptiveExtension();
    }

}
